﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using MemcachedProviders.Cache;
using sBlog.Net.Common;
using sBlog.Net.DependencyManagement;
using sBlog.Net.Domain.Entities;
using sBlog.Net.Domain.Interfaces;
using sBlog.Net.FluentExtensions;
using sBlog.Net.Models;

namespace sBlog.Net.Controllers
{
    public class AuthorController : Controller
    {
        private readonly int _postsPerPage;
        private readonly IPost _postRepository;
        private readonly IUser _userRepository;
        private readonly IFollow _followRepository;
        private readonly ISettings SettingsRepository;

        public AuthorController()
        {
            _postRepository = InstanceFactory.CreatePostInstance();
            _userRepository = InstanceFactory.CreateUserInstance();
            _followRepository = InstanceFactory.CreateFollowInstance();
            SettingsRepository = InstanceFactory.CreateSettingsInstance();
            _postsPerPage = SettingsRepository.BlogPostsPerPage;
        }

        protected int GetUserId()
        {
            var userId = -1;
            if (Request.IsAuthenticated)
            {
                var userIdentity = (IUserInfo)User.Identity;
                userId = Int32.Parse(userIdentity.UserId);
            }
            return userId;
        }

        protected string GetRootUrl()
        {
            return string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
        }

        [Authorize]
        public ActionResult AuthorListing(int? pageNumber)
        {
            var pgNumber = pageNumber ?? 1;
            var posts = GetPostsInternal();
            var users = _userRepository.GetAllUsers().Where(u => u.UserActiveStatus == 1).ToList();
            var totalPages = (int)Math.Ceiling((decimal)users.Count / _postsPerPage);
            var authorListingViewModel = GetAuthorViewModel(pgNumber, totalPages);
            authorListingViewModel.BlogName = SettingsRepository.BlogName;
            authorListingViewModel.BlogCaption = SettingsRepository.BlogCaption;
            authorListingViewModel.CurrentPageNumber = pageNumber.HasValue ? pageNumber.Value : 1;

            var authorItems = users.Skip((pgNumber - 1) * _postsPerPage)
                                       .Take(_postsPerPage).Select(u => new AuthorModel { UserID = u.UserID, UserName = u.UserName, UserDisplayName = u.UserDisplayName }).ToList();
            authorItems.ForEach(author =>
                {
                    author.Posts = posts.Where(p => p.EntryType == 1 && p.OwnerUserID == author.UserID && !p.IsPrivate).ToList();
                });
            authorListingViewModel.Authors = authorItems;
            return View(authorListingViewModel);
        }

        [Authorize]
        public ActionResult PostsByAuthor(string authorName, int? pageNumber)
        {
            var user = MemcaheService.GetUserObjByUserName(authorName);

            List<PostEntity> authorPosts = null;

            if (user != null)
            {
                authorPosts = MemcaheService.GetPostsByUserID(user.UserID);
            }

            var blogPostModel = authorPosts.GetBlogPostPageViewModel(1, SettingsRepository, _postRepository, GetRootUrl());
            blogPostModel.AuthorName = authorName;
            blogPostModel.AuthorDisplayName = user != null ? user.UserDisplayName : authorName;
            return View(blogPostModel);
        }

        public JsonResult loadFollowByType(string followType, int ownerUserID)
        {
            var stringHtml = string.Empty;
            var user = _userRepository.GetAllUsers().SingleOrDefault(u => u.UserID == ownerUserID);

            var following = _followRepository.GetFollowByFollowingUserID(user.UserID);
            var follower = _followRepository.GetFollowByFollowerUserID(user.UserID);

            user.Followers = new List<UserEntity>();
            user.Followings = new List<UserEntity>();

            if (followType == "follower")
            {
                foreach (FollowEntity followerEntity in follower)
                {
                    var us = _userRepository.GetUserObjByUserID(followerEntity.FollowingUserID);
                    user.Followers.Add(us);
                }
                stringHtml = RenderPartialViewToString("RenderFolow", user.Followers);
            }
            else if (followType == "following")
            {
                foreach (FollowEntity followingEntity in following)
                {
                    var us = _userRepository.GetUserObjByUserID(followingEntity.FollowerUserID);
                    user.Followings.Add(us);
                }
                stringHtml = RenderPartialViewToString("RenderFolow", user.Followings);
            }

            return Json(stringHtml, JsonRequestBehavior.AllowGet);
        }

        public JsonResult LoadMoreByAuthor(string authorName, int pageNumber)
        {
            var user = MemcaheService.GetUserObjByUserName(authorName);
            List<PostEntity> authorPosts = null;
            if (user != null)
            {
                authorPosts = MemcaheService.GetPostsByUserIdWithPage(user.UserID, pageNumber, 10);
            }

            var blogPostModel = authorPosts.GetBlogPostPageViewModel(1, SettingsRepository, _postRepository, GetRootUrl());
            blogPostModel.AuthorName = authorName;
            blogPostModel.AuthorDisplayName = user != null ? user.UserDisplayName : authorName;

            var stringHtml = RenderPartialViewToString("RenderPostItem", blogPostModel);
            return Json(stringHtml, JsonRequestBehavior.AllowGet);
        }


        protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);
                return sw.GetStringBuilder().ToString();
            }
        }

        private IEnumerable<PostEntity> GetPostsInternal()
        {
            var posts = GetProcessedPosts(MemcaheService.GetPosts(GetUserId()));
            return posts;
        }

        private static List<PostEntity> GetProcessedPosts(List<PostEntity> postList)
        {
            postList.ForEach(p =>
            {
                if (p.IsPrivate)
                    p.PostTitle = string.Format("[Private] {0}", p.PostTitle);
            });
            return postList;
        }

        private static AuthorListingViewModel GetAuthorViewModel(int currentPage, int totalPages)
        {
            return new AuthorListingViewModel
            {
                NextPageValid = currentPage != 1 && totalPages > 1,
                NextPageNumber = currentPage - 1,
                PreviousPageValid = currentPage < totalPages && currentPage != totalPages,
                PreviousPageNumber = currentPage + 1
            };
        }

        public JsonResult follow(int followerUserId)
        {
            string strText = string.Empty;
            FollowEntity followCheck = _followRepository.GetByFolowingUserIDAndFolowerUserID(GetUserId(), followerUserId);

            if (followCheck != null)
            {
                _followRepository.DeleteFollowByFollowID(followCheck.FollowID);
                strText = "/Content/Images/MlogThem/follow.png";
                //strText = "+ Follow";
            }
            else
            {
                FollowEntity follow = new FollowEntity();
                follow.FollowingUserID = GetUserId();
                follow.FollowerUserID = followerUserId;
                _followRepository.AddFollow(follow);
                strText = "/Content/Images/MlogThem/followed.png";
                //strText = "- UnFollow";
            }

            return Json(strText, JsonRequestBehavior.AllowGet);
        }

        public JsonResult updateBlash(string blash)
        {
            _userRepository.UpdateSplash(GetUserId(), blash);

            UserEntity user = MemcaheService.GetUserObjByUserID(GetUserId());
            DistCache.Remove(MemCacheKey.KeyGetUserObjByUserName + user.UserName);

            return Json(blash, JsonRequestBehavior.AllowGet);
        }

        public JsonResult updateAvatar(string Avatar)
        {
            string imgUrl = Avatar;
            string[] words = Avatar.Split('/');
            Avatar = words[words.Count()].ToString();

            _userRepository.UpdateAvatar(GetUserId(), Avatar);

            UserEntity user = MemcaheService.GetUserObjByUserID(GetUserId());
            DistCache.Remove(MemCacheKey.KeyGetUserObjByUserName + user.UserName);

            return Json(imgUrl, JsonRequestBehavior.AllowGet);
        }

        public JsonResult updateAvatarFace(string Avatar, int userId)
        {
            _userRepository.UpdateAvatarFace(userId, Avatar);

            UserEntity user = MemcaheService.GetUserObjByUserID(GetUserId());
            DistCache.Remove(MemCacheKey.KeyGetUserObjByUserName + user.UserName);

            return Json(Avatar, JsonRequestBehavior.AllowGet);
        }

        public JsonResult updateCover(string Cover)
        {
            _userRepository.UpdateCover(GetUserId(), Cover);

            UserEntity user = MemcaheService.GetUserObjByUserID(GetUserId());
            DistCache.Remove(MemCacheKey.KeyGetUserObjByUserName + user.UserName);

            return Json(Cover, JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            _postRepository.Dispose();
            _userRepository.Dispose();
            _followRepository.Dispose();
        }
    }
}
